﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using HA.Data;
using HAMath;
using System.Windows.Forms;
namespace HA.ModFlow.Controls.Windows.InterOptionTemporary
{
    /// <summary>
    /// winEditVariog.xaml 的交互逻辑
    /// </summary>
    public partial class winEditVariog : Window
    {
        public winEditVariog(Scatter2D scatter2d, KrigingOption option)
        {          
            InitializeComponent();
            this._scatter2d = scatter2d;
            this.KrigOption = (KrigingOption)option.Clone();
            if (this.KrigOption.ModelVariogram == null)
            {

                this.KrigOption.ModelVariogram = new HAMath.ModelVariogram(HAMath.ModelType.Spherical, 33.35, 0.5, 50.0);
            }
            this.DataContext = this.KrigOption;
            this.lstExperiment.ItemsSource = this.KrigOption.ExperimentVariogram;
            if (this.lstExperiment.Items.Count > 0)
            {
                this.lstExperiment.SelectedIndex = this.lstExperiment.Items.Count - 1;
            }
        }

      

        KrigingOption _krigOption = new KrigingOption();

        public KrigingOption KrigOption
        {
            get { return _krigOption; }
            set { _krigOption = value; }
        }
        Scatter2D _scatter2d;

        public Scatter2D Scatter2d
        {
            get { return _scatter2d; }
            set { _scatter2d = value; }
        }

     

        //private DotSpatial.Controls.Map _map;
        System.Windows.Forms.PictureBox _map;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.backGroundWorder.WorkerSupportsCancellation = true;
            this.backGroundWorder.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(backGroundWorder_RunWorkerCompleted);
            this.backGroundWorder.DoWork += new System.ComponentModel.DoWorkEventHandler(backGroundWorder_DoWork);

            this.prgBar.Visibility = System.Windows.Visibility.Hidden;
            if (this._scatter2d == null)
            {
                this.gupBoxExper.IsEnabled = false;
            }
            else
            {
                this.gupBoxExper.IsEnabled = true;
            }

            this._map = this.MapParent.Child as System.Windows.Forms.PictureBox;
            this._map.Paint += new System.Windows.Forms.PaintEventHandler(_map_Paint);

            //this._map = this.MapParent.Child as DotSpatial.Controls.Map;
            //this._map.Paint += new System.Windows.Forms.PaintEventHandler(_map_Paint);
          

            double value =this.KrigOption.ModelVariogram.Nugget;
            if (value > this.slidNugget.Maximum)
            {
                this.slidNugget.Maximum = (int)(value / 100) * 100 * 2;
            }

             value = this .KrigOption.ModelVariogram.C;
            if (value > this.slidC.Maximum)
            {
                this.slidC.Maximum = (int)(value / 100) * 100 * 2;
            }

             value = this .KrigOption.ModelVariogram.Range;
            if (value > this.sildRange.Maximum)
            {
                this.sildRange.Maximum = (int)(value / 1000) * 1000 * 2;
            }
        }

        ExperimentalVariogram experiment;
        void backGroundWorder_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            
            this.CalExpeimentVariogram(experiment);
        }

        void backGroundWorder_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            this.slidC.Maximum = maxCVarivalue;
            this.slidNugget.Maximum = maxNuggetVarivalue;
            this.sildRange.Maximum = maxRangeVarivalue;

            this.prgBar.Visibility = System.Windows.Visibility.Hidden;
            gupBoxExper.IsEnabled = true;
            this.gridNested.IsEnabled = true;
            this.txtLable.Visibility = System.Windows.Visibility.Hidden;

            if (this._map != null) this._map.Invalidate();

            this.btnOk.IsEnabled = true;
            this.btnCancal.IsEnabled = true;

        }

       

        void _map_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            //绘制坐标轴

            this.DrawAxis(e.Graphics);

            //绘制函数
            List<System.Drawing.PointF> ptLst = new List<System.Drawing.PointF>();

            for (int i = 0; i < 100; i++)
            {
                //绝对坐标
                double x = (this.sildRange.Maximum / 100 * i);
                double y = this.CalModelValue(x);
                //相对坐标。
                x = x * (this._map.Width - 60) / this.sildRange.Maximum + 30;
                y = this._map.Height - y * (this._map.Height - 60) / (this.slidC.Maximum + this.slidNugget.Maximum) - 30;
                ptLst.Add(new System.Drawing.PointF((float)x, (float)y));
            }
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.DrawLines(new System.Drawing.Pen(System.Drawing.Color.Red, 2.0f), ptLst.ToArray());

            //绘制实验变差函数值
            this.DrawVariation(e.Graphics);
        }

        /// <summary>
        /// 在控件上绘制一个坐标系
        /// </summary>
        /// <param name="g"></param>
        private void DrawAxis(System.Drawing.Graphics g)
        {
            if (this._map == null) return;
            //坐标系左下角坐标
            System.Drawing.PointF leftBottomPt = new System.Drawing.PointF(30, this._map.Height - 30);

            //坐标轴画笔
            System.Drawing.Pen AxisPen = new System.Drawing.Pen(System.Drawing.Color.Black, 3.0f);
            AxisPen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
            //刻度画笔
            System.Drawing.Pen ScalePen = System.Drawing.Pens.Gray;

            //绘制纵坐标轴
            System.Drawing.PointF leftUpPt = new System.Drawing.PointF(30, 30);
            g.DrawLine(AxisPen, leftBottomPt, new System.Drawing.PointF(leftUpPt.X, 0));

            float axisHeight = leftUpPt.Y - leftBottomPt.Y;

            //绘制纵向刻度

            //刻度值字体、颜色
            System.Drawing.Font strFont = new System.Drawing.Font("", 8.0f);
            System.Drawing.SolidBrush strBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);

            for (int i = 0; i < 6; i++)
            {
                System.Drawing.PointF leftPt = new System.Drawing.PointF(leftBottomPt.X - 10, leftBottomPt.Y + i * axisHeight / 5);
                System.Drawing.PointF rightPt = new System.Drawing.PointF(leftBottomPt.X, leftPt.Y);
                g.DrawLine(ScalePen, leftPt, rightPt);

                string scaleStr = ((this.slidC.Maximum + this.slidNugget.Maximum) / 5 * i).ToString();
                System.Drawing.PointF strPt = new System.Drawing.PointF(0, leftPt.Y - g.MeasureString(scaleStr, strFont).Height / 2);
                g.DrawString(scaleStr, strFont, strBrush, strPt);

                if (i == 5) break;

                for (int j = 1; j < 5; j++)
                {
                    System.Drawing.PointF temLeftPt = new System.Drawing.PointF(leftBottomPt.X - 5, leftBottomPt.Y + i * axisHeight / 5 + j * axisHeight / 5 / 5);
                    System.Drawing.PointF temRightPt = new System.Drawing.PointF(leftBottomPt.X, temLeftPt.Y);
                    g.DrawLine(ScalePen, temLeftPt, temRightPt);
                }
            }


            //绘制横坐标轴
            System.Drawing.PointF rightBottomPt = new System.Drawing.PointF(this._map.Width - 30, this._map.Height - 30);
            g.DrawLine(AxisPen, leftBottomPt, new System.Drawing.PointF(this._map.Width, rightBottomPt.Y));

            float axisWidth = rightBottomPt.X - leftBottomPt.X;

            //绘制横向刻度
            for (int i = 0; i < 11; i++)
            {
                System.Drawing.PointF upPt = new System.Drawing.PointF(leftBottomPt.X + i * axisWidth / 10, leftBottomPt.Y);
                System.Drawing.PointF bottomPt = new System.Drawing.PointF(upPt.X, leftBottomPt.Y + 10);
                g.DrawLine(ScalePen, upPt, bottomPt);

                string scaleStr = (this.sildRange.Maximum / 10 * i).ToString();
                System.Drawing.PointF strPt = new System.Drawing.PointF(upPt.X - g.MeasureString(scaleStr, strFont).Width / 2, bottomPt.Y);
                g.DrawString(scaleStr, strFont, strBrush, strPt);

                if (i == 10) break;
                for (int j = 1; j < 5; j++)
                {
                    System.Drawing.PointF temUpPt = new System.Drawing.PointF(upPt.X + j * axisWidth / 10 / 5, leftBottomPt.Y);
                    System.Drawing.PointF temBottomPt = new System.Drawing.PointF(temUpPt.X, leftBottomPt.Y + 5);
                    g.DrawLine(ScalePen, temUpPt, temBottomPt);
                }

            }



        }

        /// <summary>
        /// 计算模型变差值
        /// </summary>
        /// <param name="h"></param>
        /// <returns></returns>
        private float CalModelValue(double h)
        {
            switch (this.cboModelType.SelectedIndex)
            {
                case 0:
                    return this.CalSphericalValue(h);
                case 1:
                    return this.CalExponentialValue(h);
                    //break;
            }

            return 0;
        }

        /// <summary>
        /// 球形模型函数
        /// </summary>
        /// <param name="h"></param>
        /// <returns></returns>
        private float CalSphericalValue(double h)
        {
            double result = 0;

            if (h == 0)
            {
                if (Convert.ToDouble(this.txtRange.Text) != 0)
                {
                    result = Convert.ToDouble(this.txtNugget.Text);
                }
                else
                {
                    result = Convert.ToDouble(this.txtNugget.Text) + Convert.ToDouble(this.txtC.Text);
                }
            }
            else 
            if (h < Convert.ToDouble(this.txtRange.Text))
            {
                result = Convert.ToDouble(this.txtNugget.Text) + Convert.ToDouble(this.txtC.Text) * (1.5 * h /
                    Convert.ToDouble(this.txtRange.Text) - 0.5 * Math.Pow(h / Convert.ToDouble(this.txtRange.Text), 3));

            }
            else if (h >= Convert.ToDouble(this.txtRange.Text))
            {
                result = Convert.ToDouble(this.txtNugget.Text) + Convert.ToDouble(this.txtC.Text);
            }

            return (float)result;
        }


        private float CalExponentialValue(double h)
        {
            double result = 0;

            if (h == 0)
            {
                if (Convert.ToDouble(this.txtRange.Text) != 0)
                {
                    result = Convert.ToDouble(this.txtNugget.Text);
                }
                else
                {
                    result = Convert.ToDouble(this.txtNugget.Text) + Convert.ToDouble(this.txtC.Text);
                }
            }
            else 
            if (h < Convert.ToDouble(this.txtRange.Text))
            {
                result = Convert.ToDouble(this.txtNugget.Text) + Convert.ToDouble(this.txtC.Text) * (1 - Math.Exp(-3 * h / Convert.ToDouble(this.txtRange.Text)));
              
            }
            else if (h >= Convert.ToDouble(this.txtRange.Text))
            {
                result = Convert.ToDouble(this.txtNugget.Text) + Convert.ToDouble(this.txtC.Text);
            }

            return (float)result;
        }

        /// <summary>
        /// 绘制实验变差函数
        /// </summary>
        /// <param name="g"></param>
        private void DrawVariation(System.Drawing.Graphics g)
        {
            if (this._krigOption == null || this._krigOption.ExperimentVariogram == null ||
                this._krigOption.ExperimentVariogram.Count == 0)
                return;

            //绘制变差函数值
            foreach (ExperimentalVariogram variogram in this._krigOption.ExperimentVariogram)
            {
                if (variogram == null || variogram.Variation == null || variogram.Variation.Length == 0 ||
                    variogram.AverageDistance == null || variogram.AverageDistance.Length == 0) continue;

                List<System.Drawing.PointF> pts = new List<System.Drawing.PointF>();

                for (int i = 0; i < variogram.Variation.Length; i++)
                {
                    double x = variogram.AverageDistance[i]; //变差距离
                    double y = variogram.Variation[i];    //变差值

                    if (double.IsNaN(x) || double.IsNaN(y)) continue;
                    if (i != 0 && x == 0) continue;

                    x = x * (this._map.Width - 60) / this.sildRange.Maximum + 30;
                    y = this._map.Height - y * (this._map.Height - 60) / (this.slidC.Maximum + this.slidNugget.Maximum) - 30;

                    System.Drawing.PointF pt = new System.Drawing.PointF((float)x, (float)y);
                    g.FillEllipse(System.Drawing.Brushes.Black, pt.X - 3, pt.Y - 3, 6, 6);

                    pts.Add(pt);
                }

                g.DrawLines(System.Drawing.Pens.Black, pts.ToArray());

            }

        }



        /// <summary>
        /// 计算实绘变差值，并且坐标系的范围也由
        /// </summary>
        /// <param name="experVariogram"></param>
        private void CalExpeimentVariogram(ExperimentalVariogram experVariogram)
        {
            List<KrigingPoint> krigPts = new List<KrigingPoint>();
            List<double> values = new List<double>();
            for (int i = 0; i < this._scatter2d.DataSet.Count; i++)
            {
                KrigingPoint krigPt = new KrigingPoint(this._scatter2d.DataSet[i].X, this._scatter2d.DataSet[i].Y, this._scatter2d.DataSet[i].Values[this.index]);
                krigPts.Add(krigPt);
                values.Add(this._scatter2d.DataSet[i].Values[this.index]);
            }

            experVariogram.CalVariation(krigPts, values);


            if (this._krigOption == null || this._krigOption.ExperimentVariogram == null ||
                                        this._krigOption.ExperimentVariogram.Count == 0)
                return;

            double maxVariation = double.MinValue;
            double maxDistance = double.MinValue;

            foreach (ExperimentalVariogram variogram in this._krigOption.ExperimentVariogram)
            {
                if (variogram == null || variogram.Variation == null || variogram.Variation.Length == 0 ||
                    variogram.AverageDistance == null || variogram.AverageDistance.Length == 0) continue;

                for (int i = 0; i < variogram.Variation.Length; i++)
                {
                    if (maxDistance < variogram.AverageDistance[i]) maxDistance = variogram.AverageDistance[i]; //变差距离
                    if (maxVariation < variogram.Variation[i]) maxVariation = variogram.Variation[i];    //变差值
                }
            }

            //this.slidC.Maximum = ((int)(maxVariation / 10) + 1) * 10;
            //this.slidNugget.Maximum = ((int)(maxVariation / 10) + 1) * 10;
            //this.sildRange.Maximum = ((int)(maxDistance / 10) + 1) * 10;

            maxCVarivalue = ((int)(maxVariation / 10) + 1) * 10;
            maxNuggetVarivalue = ((int)(maxVariation / 10) + 1) * 10;
            maxRangeVarivalue = ((int)(maxDistance / 10) + 1) * 10;
            //if (this._map != null) this._map.Invalidate();

        }

        private int maxCVarivalue = 0;
        private int maxNuggetVarivalue = 0;
        private int maxRangeVarivalue = 0;

        private System.ComponentModel.BackgroundWorker backGroundWorder = new System.ComponentModel.BackgroundWorker();

        /// <summary>
        /// 添加一个实验变差函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddExperimental_Click(object sender, RoutedEventArgs e)
        {

            ExperimentalVariogram exper = new ExperimentalVariogram(VariogramType.Semivariogram);
            int index = 1;
            if (this.KrigOption.ExperimentVariogram.Count > 0)
            {
                int num = this.KrigOption.ExperimentVariogram.Count - 1;
                ExperimentalVariogram experVar = this.KrigOption.ExperimentVariogram[num];
                index = Convert.ToInt16(experVar.Name.Substring(experVar.Name.Length - 1, (experVar.Name.Length - exper.Name.Length)));
                index++;
            }
            exper.Name = exper.Name + index;
            HA.ModFlow.Controls.Windows.DataOperation.winExperimental win = new DataOperation.winExperimental(exper);
            win.Owner = this;
            if (win.ShowDialog().Value)
            {
              
                this._krigOption.ExperimentVariogram.Add(win.Experimental);
                this.lstExperiment.Items.Refresh();
                this.lstExperiment.SelectedIndex = this.lstExperiment.Items.Count - 1;

                RunCacaluler(win.Experimental);
                //this.CalExpeimentVariogram(win.Experimental);
            }            
            if (this._map != null) this._map.Invalidate();
        
        }

        private void RunCacaluler(ExperimentalVariogram exp)
        {
            gupBoxExper.IsEnabled = false;
            this.gridNested.IsEnabled = false;
            this.prgBar.Visibility = System.Windows.Visibility.Visible;
            this.txtLable.Visibility = System.Windows.Visibility.Visible;
            experiment = exp;
            this.btnOk.IsEnabled = false ;
            this.btnCancal.IsEnabled = false ;
            this.backGroundWorder.RunWorkerAsync();
        }

        private void btnDelExperimental_Click(object sender, RoutedEventArgs e)
        {
            int index = this.lstExperiment.SelectedIndex;
            ExperimentalVariogram exper = lstExperiment.SelectedItem as ExperimentalVariogram;
            if (exper != null)
            {
                this.KrigOption.ExperimentVariogram.Remove(exper);
                this.lstExperiment.Items.Refresh();
                if (index > this.lstExperiment.Items.Count - 1)
                {
                    this.lstExperiment.SelectedIndex = this.lstExperiment.Items.Count - 1;
                }
                else
                {
                    this.lstExperiment.SelectedIndex = index;
                }
            }

            if (this._map != null) this._map.Invalidate();
        }

        /// <summary>
        /// 编辑 一个实验变差函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEditExperimental_Click(object sender, RoutedEventArgs e)
        {
            if (this.KrigOption.ExperimentVariogram.Count > 0)
            {
                ExperimentalVariogram exper = this.KrigOption.ExperimentVariogram[this.lstExperiment.SelectedIndex];
                HA.ModFlow.Controls.Windows.DataOperation.winExperimental win = new DataOperation.winExperimental(exper);
                if (win.ShowDialog().Value)
                {
                    this.KrigOption.ExperimentVariogram[this.lstExperiment.SelectedIndex] = win.Experimental;

                    RunCacaluler(win.Experimental);
                    //this.CalExpeimentVariogram(win.Experimental);
                }
            }

            if (this._map != null) this._map.Invalidate();
        }

        private void sildRange_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this._map == null) return;
            this._map.Invalidate();
        }

        private void slidC_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this._map == null) return;
            this._map.Invalidate();
        }

        private void slidNugget_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (this._map == null) return;
            this._map.Invalidate();
        }

        private void txtNugget_LostFocus(object sender, RoutedEventArgs e)
        {
            try
            {
                double value = Convert.ToDouble(this.txtNugget.Text.ToString());
                if (value > this.slidNugget.Maximum)
                {
                    this.slidNugget.Maximum = (int)(value / 100) * 100 * 2;
                }
                //if (value < this.slidNugget.Maximum / 2)
                //{
                //    while (this.slidNugget.Maximum / 2 > value)
                //    {
                //        this.slidNugget.Maximum = slidNugget.Maximum / 2;
                //        if (this.slidNugget.Maximum < 100)
                //        {
                //            this.slidNugget.Maximum = 100;
                //            break;
                //        }
                //    }
                //}
                //this.txtNugget.Text = value.ToString();
                if (this._map == null) return;
                this._map.Invalidate();
            }
            catch { }
        }

        private void txtC_LostFocus(object sender, RoutedEventArgs e)
        {
            try
            {
                double value = Convert.ToDouble(this.txtC.Text.ToString());
                if (value > this.slidC.Maximum)
                {
                    this.slidC.Maximum = (int)(value / 100) * 100 * 2;
                }
                //if (value < this.slidC.Maximum / 2)
                //{
                //    while (this.slidC.Maximum / 2 > value)
                //    {
                //        this.slidC.Maximum = slidC.Maximum / 2;
                //        if (this.slidC.Maximum < 100)
                //        {
                //            this.slidC.Maximum = 100;
                //            break;
                //        }
                //    }
                //}
                //this.txtC.Text = value.ToString();

                if (this._map == null) return;
                this._map.Invalidate();
            }
            catch { }
        }

        private void txtRange_LostFocus(object sender, RoutedEventArgs e)
        {
            try
            {
                double value = Convert.ToDouble(this.txtRange.Text.ToString());
                if (value > this.sildRange.Maximum)
                {
                    this.sildRange.Maximum = (int)(value / 1000) * 1000 * 2;
                }
                //if (value < this.sildRange.Maximum / 2)
                //{
                //    while (this.sildRange.Maximum / 2 > value)
                //    {
                //        this.sildRange.Maximum = sildRange.Maximum / 2;
                //        if (this.sildRange.Maximum < 1000)
                //        {
                //            this.sildRange.Maximum = 1000;
                //            break;
                //        }
                //    }
                //}

                //this.txtRange.Text = value.ToString();
                if (this._map != null)
                {
                    this._map.Invalidate();
                }
            }
            catch { }
        }

        private void btnOk_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
            this.Close();
        }

        private void btnCancal_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        int index = 0;//选择数据
        private void btnSelectScatter_Click(object sender, RoutedEventArgs e)
        {
            if (this._scatter2d != null)
            {
                int[] indexInList = new int[1];
                HA.ModFlow.Controls.Windows.MapData.winConceptualFrame win = new MapData.winConceptualFrame(this._scatter2d, ChooseConfigeType.Scatter2DValueChoose, indexInList);
                win.Owner = this;
                win.ResizeMode = ResizeMode.NoResize;
                win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                if (win.ShowDialog() == true)
                {
                    if (indexInList != null)
                    {
                        if (indexInList.Length > 0)
                        {
                            index = indexInList[0];
                        }
                    }
                }
            }
        }

        private void cboModelType_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (this._map != null)
            {
                this._map.Invalidate();
            }
        }

    }

    public class ConvertToModelType : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            HAMath.ModelType type = (HAMath.ModelType)value;
            int index = 0;
            switch (type)
            {
                case HAMath.ModelType.Spherical:
                    index = 0;
                    break;
                case HAMath.ModelType.Exponential:
                    index = 1;
                    break;
                //case HAMath.ModelType.Gaussian:
                //    index = 2;
                //    break;
                //case HAMath.ModelType.Power:
                //    index = 3;
                //    break;
            }
            return index;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            HAMath.ModelType type = HAMath.ModelType.Spherical;
            int index = (int)value;
            switch (index)
            {
                case 0:
                    type = HAMath.ModelType.Spherical;
                    break;
                case 1:
                    type = HAMath.ModelType.Exponential;
                    break;
                //case 2:
                //    type = HAMath.ModelType.Gaussian;
                //    break;
                //case 3:
                //    type = HAMath.ModelType.Power;
                //    break;
            }
            return type;
        }
    }
}
